package timer
{
    import flash.events.*;
    import flash.utils.*;

    /**
     * 程序中尽量不要使用Timer和系统的setTimeout ,setInterval 等。
     * 测试OK
     * @author Ryan
     * 
     */	
    public class TimerClock 
    {
        private var _maxID:uint;
        private var _delay:uint;
        private var _timer:Timer;
        private var _threads:Object;
        private var _startTime:uint;
		
        private var _sleeping:Object;
		private var _sleepingQueue:Object;
		
		private var _run:Boolean;
		
		private var _timerList:Dictionary;
		private var _timerFunc:Dictionary;
		
        private static var _instance:TimerClock;
		
		//耗时检测
		private var _costTestDic : Object = null;
		private var _testHandler : Number = 0;
		
		
		public function startTest(callback:Function):void
		{
			if(_costTestDic != null || _testHandler > 0){
				stopTest();
			}
			
			var onTimeout : Function = function():void
			{
				callback( _costTestDic );
			};
			
			_costTestDic = new Dictionary();
			
			_testHandler = flash.utils.setTimeout(onTimeout, 10*1000);
		}
		
		private function stopTest():void
		{
			_costTestDic = null;
			flash.utils.clearTimeout(_testHandler);
			_testHandler = 0;
		}
		
        public static function getInstance(delay:uint = 10) : TimerClock
        {
            if (_instance == null)
            {
                _instance = new TimerClock(delay);
            }// end if
            return _instance;
        }// end function

        public function TimerClock(delay:uint = 10)
        {
            _maxID = 1;
            _delay = delay;
			
			_timerList = new Dictionary();
			_timerFunc = new Dictionary();
        }// end function

        public function stop() : void
        {
			// 暂时不允许stop
			return;
            if ( _run ) {
                _threads = {};
                initSleepingList();
				_run = false;
            } 
        } 

        private function suspend(threadId:uint, time:uint) : void
        {
			addToSleeping(threadId, time);
        } 

        public function start() : void {
            if ( !_run ) {
                _startTime = getTimer();
                _threads = {};
				initSleepingList();
				_run = true;
				callRun();
            }  
        }
		
		private function initSleepingList():void
		{
			_sleeping = {};
			_sleepingQueue = {};
		}
		private function popSleeping():Array
		{
			//离定时器启动总共的时间片数
			var piecesLast : Number = Math.ceil((getTimer() - _startTime) / _delay);
			
			var arr : Array = [];
			var node : Object = _sleepingQueue.head;
			while(true){
				if( !node || node.index >= piecesLast ){
					break;
				}else{
					var threadArr : Array = node.obj as Array;
					for(var i:int=0; i<threadArr.length; i++){
						arr.push( threadArr[i] );
					}
					_sleeping[node.index] = null;
					_sleepingQueue.head = node.next;
					node = node.next; //步进
				}
			}
		
			return arr;
		}
		private function addToSleeping(threadId:uint, time:uint):void
		{
			//离定时器启动总共的时间片数
			var piecesLast : Number = Math.ceil((getTimer() - _startTime) / _delay);
			
			var piece:Number = (time / _delay >> 0) + piecesLast;
			
			if (!_sleeping[piece])
			{
				_sleeping[piece] = [];
				var newNode : Object = {obj:_sleeping[piece], index:piece, next:null};
				
				if(!_sleepingQueue.head){
					_sleepingQueue.head = newNode;
				}else{
					var node : Object = _sleepingQueue.head;
					if(piece < node.index){
						_sleepingQueue.head = newNode;
						newNode.next = node;
					}else{
						while(true){
							var nextNode : Object = node.next;
							if( nextNode && piece < nextNode.index ){
								node.next = newNode;
								newNode.next = nextNode;
								break;
							}else if(!nextNode){ //到了队列尾还没找到更小的，则放到最后
								node.next = newNode;
								break;
							}else{
								node = node.next;
							}
						}
					}
				}
			}

			_sleeping[piece].push(threadId);
		}
		
		private function callRun():void
		{
			try
			{
				run(null);
			}
			catch( error:Error )
			{
				throw error;
			}
			finally
			{
				if( _run ){
					flash.utils.setTimeout(callRun,_delay);
				}
			}
		}
		
		public static var lastThreadNum:Number;

        private function run(evt:TimerEvent) : void
        { 
			var timeStart : Number = new Date().getTime();//测试消耗
			
			var a:Array = popSleeping();
            var i:uint = 0;
            var length:uint = a.length;
			lastThreadNum = length;
			
			//测试join消耗
			var timeAfterJoin : Number = new Date().getTime();
			if(_costTestDic){
				if(!_costTestDic.joinCost) _costTestDic.joinCost = 0;
				_costTestDic.joinCost += (timeAfterJoin - timeStart);
			}
			
			var errorInstance:Error = null;
			
            while (i < length)
			{
                var thd:Thread = _threads[a[i]];
				
                if ( thd )
				{
					try
					{
						//测试执行消耗
						var timeBeforeHandler : Number = new Date().getTime();
						
						thd.listen.apply(null, thd.args);
						
						//测试执行消耗
						var timeAfterHandler : Number = new Date().getTime();
						if(_costTestDic){
							var funcName : String = String(thd.listen);
							if(!_costTestDic[funcName]) _costTestDic[funcName] = 0;
							_costTestDic[funcName] += (timeAfterHandler - timeBeforeHandler);
						}
					}
					catch( error:Error )
					{
						errorInstance = error;
					}
					finally
					{
						if (!thd.repeat)
						{
							remove(a[i]);
						}
						else
						{
							suspend(a[i], thd.delay);
						} 
					}
                } 
                i++;
            } 
			
			if( evt ) evt.updateAfterEvent();
			
			//测试总消耗
			var timeFinish : Number = new Date().getTime();
			if(_costTestDic){
				if(!_costTestDic.totalCost) _costTestDic.totalCost = 0;
				_costTestDic.totalCost += (timeFinish - timeStart);
			}
			
			if ( errorInstance )
			{
				throw errorInstance;
			}
        } 

        public function setInterval(func:Function, delay:uint, ... args) : uint
        {
			
            _threads[_maxID] = new Thread(func, delay, true, args);
            suspend(_maxID, delay);
            return _maxID++;
        } 

        public function setTimeout(func:Function, delay:uint, ... args) : uint
        {
			
            _threads[_maxID] = new Thread(func, delay, false, args);
            suspend(_maxID, delay);
            return _maxID++;
        } 

		public function remove(threadId:uint) : void
        {
			
			
            _threads[threadId] = null;
            delete _threads[threadId];
        } 
        
        public function clearAndStart() : void {
        	stop();
        	start();
        }
		
    }
}
